/**
 * 实用工具函数集合
 * 提供RSS解析、时间格式化、文本处理等功能
 */

import type { Article, RSSFeed } from '@/types';

/**
 * 时间格式化工具
 */
export class TimeUtils {
  /**
   * 格式化相对时间
   * @param {Date} date - 日期对象
   * @returns {string} 格式化后的相对时间字符串
   */
  static formatRelativeTime(date: Date): string {
    const now = new Date();
    const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000);
    
    if (diffInSeconds < 60) {
      return '刚刚';
    }
    
    const diffInMinutes = Math.floor(diffInSeconds / 60);
    if (diffInMinutes < 60) {
      return `${diffInMinutes}分钟前`;
    }
    
    const diffInHours = Math.floor(diffInMinutes / 60);
    if (diffInHours < 24) {
      return `${diffInHours}小时前`;
    }
    
    const diffInDays = Math.floor(diffInHours / 24);
    if (diffInDays < 7) {
      return `${diffInDays}天前`;
    }
    
    const diffInWeeks = Math.floor(diffInDays / 7);
    if (diffInWeeks < 4) {
      return `${diffInWeeks}周前`;
    }
    
    const diffInMonths = Math.floor(diffInDays / 30);
    if (diffInMonths < 12) {
      return `${diffInMonths}个月前`;
    }
    
    const diffInYears = Math.floor(diffInDays / 365);
    return `${diffInYears}年前`;
  }
  
  /**
   * 格式化日期为本地化字符串
   * @param {Date} date - 日期对象
   * @param {string} locale - 语言环境，默认为中文
   * @returns {string} 格式化后的日期字符串
   */
  static formatDate(date: Date, locale: string = 'zh-CN'): string {
    return date.toLocaleDateString(locale, {
      year: 'numeric',
      month: 'long',
      day: 'numeric',
    });
  }
  
  /**
   * 格式化日期时间为本地化字符串
   * @param {Date} date - 日期对象
   * @param {string} locale - 语言环境，默认为中文
   * @returns {string} 格式化后的日期时间字符串
   */
  static formatDateTime(date: Date, locale: string = 'zh-CN'): string {
    return date.toLocaleString(locale, {
      year: 'numeric',
      month: 'short',
      day: 'numeric',
      hour: '2-digit',
      minute: '2-digit',
    });
  }
}

/**
 * 文本处理工具
 */
export class TextUtils {
  /**
   * 截取文本并添加省略号
   * @param {string} text - 原始文本
   * @param {number} maxLength - 最大长度
   * @returns {string} 截取后的文本
   */
  static truncate(text: string, maxLength: number): string {
    if (text.length <= maxLength) {
      return text;
    }
    return text.slice(0, maxLength) + '...';
  }
  
  /**
   * 清理HTML标签
   * @param {string} html - HTML字符串
   * @returns {string} 清理后的纯文本
   */
  static stripHtml(html: string): string {
    const div = document.createElement('div');
    div.innerHTML = html;
    return div.textContent || div.innerText || '';
  }
  
  /**
   * 提取文本摘要
   * @param {string} content - 文章内容
   * @param {number} maxLength - 摘要最大长度
   * @returns {string} 文章摘要
   */
  static extractSummary(content: string, maxLength: number = 200): string {
    const cleanText = this.stripHtml(content);
    return this.truncate(cleanText, maxLength);
  }
  
  /**
   * 高亮搜索关键词
   * @param {string} text - 原始文本
   * @param {string} keyword - 搜索关键词
   * @returns {string} 高亮后的HTML字符串
   */
  static highlightKeyword(text: string, keyword: string): string {
    if (!keyword) return text;
    
    const regex = new RegExp(`(${keyword})`, 'gi');
    return text.replace(regex, '<mark class="bg-yellow-200 px-1 rounded">$1</mark>');
  }
}

/**
 * URL处理工具
 */
export class UrlUtils {
  /**
   * 验证URL格式
   * @param {string} url - URL字符串
   * @returns {boolean} 是否为有效URL
   */
  static isValidUrl(url: string): boolean {
    try {
      new URL(url);
      return true;
    } catch {
      return false;
    }
  }
  
  /**
   * 获取域名
   * @param {string} url - URL字符串
   * @returns {string} 域名
   */
  static getDomain(url: string): string {
    try {
      const urlObj = new URL(url);
      return urlObj.hostname;
    } catch {
      return '';
    }
  }
  
  /**
   * 获取网站图标URL
   * @param {string} url - 网站URL
   * @returns {string} 图标URL
   */
  static getFaviconUrl(url: string): string {
    const domain = this.getDomain(url);
    if (!domain) return '';
    
    return `https://www.google.com/s2/favicons?domain=${domain}&sz=32`;
  }
}

/**
 * RSS解析工具
 */
export class RSSParser {
  /**
   * 解析RSS XML内容
   * @param {string} xmlContent - RSS XML内容
   * @returns {Promise<{ feed: Partial<RSSFeed>, articles: Partial<Article>[] }>} 解析结果
   */
  static async parseRSS(xmlContent: string): Promise<{
    feed: Partial<RSSFeed>;
    articles: Partial<Article>[];
  }> {
    try {
      const parser = new DOMParser();
      const doc = parser.parseFromString(xmlContent, 'text/xml');
      
      // 检查解析错误
      const parseError = doc.querySelector('parsererror');
      if (parseError) {
        throw new Error('XML解析失败');
      }
      
      // 判断是RSS还是Atom
      const isAtom = doc.querySelector('feed') !== null;
      
      if (isAtom) {
        return this.parseAtom(doc);
      } else {
        return this.parseRSSXML(doc);
      }
    } catch (error) {
      console.error('RSS解析失败:', error);
      throw error;
    }
  }
  
  /**
   * 解析RSS 2.0格式
   * @param {Document} doc - XML文档对象
   * @returns {{ feed: Partial<RSSFeed>, articles: Partial<Article>[] }} 解析结果
   */
  private static parseRSSXML(doc: Document): {
    feed: Partial<RSSFeed>;
    articles: Partial<Article>[];
  } {
    const channel = doc.querySelector('channel');
    if (!channel) {
      throw new Error('无效的RSS格式');
    }
    
    // 解析Feed信息
    const feed: Partial<RSSFeed> = {
      title: this.getTextContent(channel, 'title') || '未知RSS源',
      description: this.getTextContent(channel, 'description') || '',
      url: this.getTextContent(channel, 'link') || '',
    };
    
    // 解析文章列表
    const items = Array.from(channel.querySelectorAll('item'));
    const articles: Partial<Article>[] = items.map((item, index) => {
      const pubDateStr = this.getTextContent(item, 'pubDate');
      const publishedAt = pubDateStr ? new Date(pubDateStr) : new Date();
      
      return {
        id: this.generateArticleId(item, index),
        title: this.getTextContent(item, 'title') || '无标题',
        content: this.getTextContent(item, 'description') || this.getTextContent(item, 'content:encoded') || '',
        summary: this.getTextContent(item, 'description') || '',
        url: this.getTextContent(item, 'link') || '',
        publishedAt,
        author: this.getTextContent(item, 'author') || this.getTextContent(item, 'dc:creator') || '',
        isRead: false,
        isFavorited: false,
      };
    });
    
    return { feed, articles };
  }
  
  /**
   * 解析Atom格式
   * @param {Document} doc - XML文档对象
   * @returns {{ feed: Partial<RSSFeed>, articles: Partial<Article>[] }} 解析结果
   */
  private static parseAtom(doc: Document): {
    feed: Partial<RSSFeed>;
    articles: Partial<Article>[];
  } {
    const feedElement = doc.querySelector('feed');
    if (!feedElement) {
      throw new Error('无效的Atom格式');
    }
    
    // 解析Feed信息
    const feed: Partial<RSSFeed> = {
      title: this.getTextContent(feedElement, 'title') || '未知RSS源',
      description: this.getTextContent(feedElement, 'subtitle') || '',
      url: this.getLinkHref(feedElement, 'alternate') || '',
    };
    
    // 解析文章列表
    const entries = Array.from(feedElement.querySelectorAll('entry'));
    const articles: Partial<Article>[] = entries.map((entry, index) => {
      const publishedStr = this.getTextContent(entry, 'published') || this.getTextContent(entry, 'updated');
      const publishedAt = publishedStr ? new Date(publishedStr) : new Date();
      
      return {
        id: this.generateArticleId(entry, index),
        title: this.getTextContent(entry, 'title') || '无标题',
        content: this.getTextContent(entry, 'content') || this.getTextContent(entry, 'summary') || '',
        summary: this.getTextContent(entry, 'summary') || '',
        url: this.getLinkHref(entry, 'alternate') || '',
        publishedAt,
        author: this.getAuthorName(entry) || '',
        isRead: false,
        isFavorited: false,
      };
    });
    
    return { feed, articles };
  }
  
  /**
   * 获取元素文本内容
   * @param {Element} parent - 父元素
   * @param {string} selector - 选择器
   * @returns {string} 文本内容
   */
  private static getTextContent(parent: Element, selector: string): string {
    const element = parent.querySelector(selector);
    return element?.textContent?.trim() || '';
  }
  
  /**
   * 获取链接href属性
   * @param {Element} parent - 父元素
   * @param {string} rel - rel属性值
   * @returns {string} href属性值
   */
  private static getLinkHref(parent: Element, rel: string): string {
    const link = parent.querySelector(`link[rel="${rel}"]`);
    return link?.getAttribute('href') || '';
  }
  
  /**
   * 获取作者名称
   * @param {Element} entry - 文章元素
   * @returns {string} 作者名称
   */
  private static getAuthorName(entry: Element): string {
    const authorElement = entry.querySelector('author name');
    if (authorElement) {
      return authorElement.textContent?.trim() || '';
    }
    
    const author = entry.querySelector('author');
    return author?.textContent?.trim() || '';
  }
  
  /**
   * 生成文章ID
   * @param {Element} item - 文章元素
   * @param {number} index - 索引
   * @returns {string} 文章ID
   */
  private static generateArticleId(item: Element, index: number): string {
    // 尝试获取GUID或ID
    const guid = this.getTextContent(item, 'guid') || this.getTextContent(item, 'id');
    if (guid) {
      return guid;
    }
    
    // 使用链接作为ID
    const link = this.getTextContent(item, 'link') || this.getLinkHref(item, 'alternate');
    if (link) {
      return btoa(link).replace(/[^a-zA-Z0-9]/g, '').slice(0, 16);
    }
    
    // 使用标题和索引生成ID
    const title = this.getTextContent(item, 'title');
    const baseId = title ? btoa(title).replace(/[^a-zA-Z0-9]/g, '') : 'article';
    return `${baseId}_${index}_${Date.now()}`;
  }
}

/**
 * 存储工具
 */
export class StorageUtils {
  /**
   * 保存数据到localStorage
   * @param {string} key - 存储键
   * @param {any} data - 要保存的数据
   */
  static save(key: string, data: any): void {
    try {
      const jsonString = JSON.stringify(data);
      localStorage.setItem(key, jsonString);
    } catch (error) {
      console.error('保存数据失败:', error);
    }
  }
  
  /**
   * 从localStorage读取数据
   * @param {string} key - 存储键
   * @param {any} defaultValue - 默认值
   * @returns {any} 读取的数据
   */
  static load<T>(key: string, defaultValue: T): T {
    try {
      const jsonString = localStorage.getItem(key);
      if (jsonString === null) {
        return defaultValue;
      }
      return JSON.parse(jsonString);
    } catch (error) {
      console.error('读取数据失败:', error);
      return defaultValue;
    }
  }
  
  /**
   * 删除localStorage中的数据
   * @param {string} key - 存储键
   */
  static remove(key: string): void {
    try {
      localStorage.removeItem(key);
    } catch (error) {
      console.error('删除数据失败:', error);
    }
  }
  
  /**
   * 清空localStorage
   */
  static clear(): void {
    try {
      localStorage.clear();
    } catch (error) {
      console.error('清空数据失败:', error);
    }
  }
}

/**
 * 通知工具
 */
export class NotificationUtils {
  /**
   * 请求通知权限
   * @returns {Promise<boolean>} 是否获得权限
   */
  static async requestPermission(): Promise<boolean> {
    if (!('Notification' in window)) {
      console.warn('浏览器不支持通知功能');
      return false;
    }
    
    if (Notification.permission === 'granted') {
      return true;
    }
    
    if (Notification.permission === 'denied') {
      return false;
    }
    
    const permission = await Notification.requestPermission();
    return permission === 'granted';
  }
  
  /**
   * 显示通知
   * @param {string} title - 通知标题
   * @param {string} body - 通知内容
   * @param {string} icon - 通知图标
   */
  static async showNotification(
    title: string,
    body: string,
    icon?: string
  ): Promise<void> {
    const hasPermission = await this.requestPermission();
    if (!hasPermission) {
      return;
    }
    
    try {
      const notification = new Notification(title, {
        body,
        icon: icon || '/favicon.ico',
        badge: '/favicon.ico',
        tag: 'rss-reader',
        renotify: true,
      });
      
      // 自动关闭通知
      setTimeout(() => {
        notification.close();
      }, 5000);
    } catch (error) {
      console.error('显示通知失败:', error);
    }
  }
}

/**
 * 防抖函数
 * @param {Function} func - 要防抖的函数
 * @param {number} delay - 延迟时间（毫秒）
 * @returns {Function} 防抖后的函数
 */
export function debounce<T extends (...args: any[]) => any>(
  func: T,
  delay: number
): (...args: Parameters<T>) => void {
  let timeoutId: ReturnType<typeof setTimeout>;
  
  return (...args: Parameters<T>) => {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => func(...args), delay);
  };
}

/**
 * 节流函数
 * @param {Function} func - 要节流的函数
 * @param {number} delay - 延迟时间（毫秒）
 * @returns {Function} 节流后的函数
 */
export function throttle<T extends (...args: any[]) => any>(
  func: T,
  delay: number
): (...args: Parameters<T>) => void {
  let lastCall = 0;
  
  return (...args: Parameters<T>) => {
    const now = Date.now();
    if (now - lastCall >= delay) {
      lastCall = now;
      func(...args);
    }
  };
}

/**
 * 生成唯一ID
 * @returns {string} 唯一ID
 */
export function generateId(): string {
  return Math.random().toString(36).substr(2, 9) + Date.now().toString(36);
}

/**
 * 深拷贝对象
 * @param {T} obj - 要拷贝的对象
 * @returns {T} 拷贝后的对象
 */
export function deepClone<T>(obj: T): T {
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }
  
  if (obj instanceof Date) {
    return new Date(obj.getTime()) as unknown as T;
  }
  
  if (obj instanceof Array) {
    return obj.map(item => deepClone(item)) as unknown as T;
  }
  
  if (typeof obj === 'object') {
    const clonedObj = {} as { [key: string]: any };
    for (const key in obj) {
      if (obj.hasOwnProperty(key)) {
        clonedObj[key] = deepClone(obj[key]);
      }
    }
    return clonedObj as T;
  }
  
  return obj;
}